package perform.database;

import java.lang.reflect.Field;

import perform.annotations.Column;
import perform.annotations.ID;
import perform.constants.Index;
import perform.constants.Types;
import perform.mappings.TypeMappings;

public class SimpleColumnProcessor implements ColumnProcessor {
	
	private Field field;
	private Column column;
	private ID id;
	
	private String name;
	private String type;
	private int length;
	private int precision;
	private String[] values;
	
	private String columnDefinition;
	private String indexDefinition;
	
	public SimpleColumnProcessor(Field field, String name){
		this.field = field;
		this.name = name;
		column = field.getAnnotation(Column.class);
		id = field.isAnnotationPresent(ID.class) ? field.getAnnotation(ID.class) : null;
		if(column.type().equals(Types.NOT_SPECIFIED)){
			type = TypeMappings.type(field.getType());
		} else {
			type = column.type().toString().toLowerCase();
		}
		length = column.length() > 0 ? column.length() : TypeMappings.length(type);
		precision = column.precision();
		if(field.getType().isEnum()){
			Object[] vals = field.getType().getEnumConstants();
			values = new String[vals.length];
			for (int i = 0; i < vals.length; i++) {
				values[i] = vals[i].toString();
			}
		}
		buildColumnDefinition();
		buildIndexDefinition();
	}
	
	private void buildColumnDefinition(){
		StringBuilder builder = new StringBuilder("\t`").append(name).append("` ");
		builder.append(type);
		if(length > 0 && precision > 0){
			builder.append(" (").append(length).append(",").append(precision).append(")");
		} else if(length > 0) {
			builder.append(" (").append(length).append(")");
		} else if(type.equals("enum")){
			builder.append(" ( '");
			for (int i = 0; i < values.length; i++) {
				builder.append(values[i]).append("' , '");
			}
			builder.replace(builder.lastIndexOf(","), builder.length(), ")");
		}
		if(getDefaultValue() != null){
			builder.append(" default ").append(getDefaultValue());
		}
		if(!isNullable()){
			builder.append(" not null");
		}
		if(id != null && id.autoIncrement()){
			builder.append(" auto_increment");
		}
		builder.append(" ,\n");
		columnDefinition = builder.toString();
	}
	private void buildIndexDefinition(){
		if(isIndex()){
			StringBuilder builder = new StringBuilder();
			Index index = getIndex();
			switch (index) {
			case INDEX:
				builder.append("\tindex ( `").append(name).append("` ) ,\n");
				break;
			case UNIQUE:
				builder.append("\tunique ( `").append(name).append("` ) ,\n");
				break;
			case FULLTEXT:
				builder.append("\tfulltext ( `").append(name).append("` ) ,\n");
				break;
			default:
				builder.append("\tprimary key ( `").append(name).append("` ) ,\n");
				break;
			}
			indexDefinition = builder.toString();
		} else {
			indexDefinition = null;
		}
	}

	@Override
	public Field getField(){
		return field;
	}
	@Override
	public String getName() {
		return name;
	}
	@Override
	public String getType() {
		return type;
	}
	@Override
	public int getLength() {
		return length;
	}
	@Override
	public int getPrecision() {
		return column.precision();
	}
	@Override
	public String[] getValues() {
		return values;
	}
	@Override
	public String getDefaultValue() {
		return column.defaultValue().equals("") ? null : column.defaultValue();
	}
	@Override
	public boolean isNullable() {
		return column.nullable();
	}
	@Override
	public boolean isIndex() {
		return (!column.index().equals(Index.NONE) || id != null);
	}
	@Override
	public boolean hasConstraints() {
		return false;
	}
	@Override
	public Index getIndex() {
		return column.index();
	}
	@Override
	public String getColumnDefinition() {
		return columnDefinition;
	}
	@Override
	public String getIndexDefinition() {
		return indexDefinition;
	}
	@Override
	public String getForeignKeyDefinition() {
		return null;
	}
	
	@Override
	public boolean equals(Object obj) {
		if(obj instanceof SimpleColumnProcessor){
			if(field.equals(((SimpleColumnProcessor)obj).getField())){
				return true;
			}
		}
		return false;
	}

}
